home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Gold Collection / Software Vault - The Gold Collection (American Databankers) (1993).ISO / cdr53 / frasrc18.zip / HELP.C < prev    next >
C/C++ Source or Header  |  1993-04-14  |  38KB  |  1,674 lines

  1. /*
  2.  * help.c
  3.  *
  4.  * This module is linked as an overlay, use ENTER_OVLY and EXIT_OVLY.
  5.  *
  6.  *
  7.  * Revision history:
  8.  *
  9.  *   2-26-90  EAN     Initial version.
  10.  *
  11.  *
  12.  */
  13.  
  14.  
  15. #ifndef TEST /* kills all those assert macros in production version */
  16. #define NDEBUG
  17. #endif
  18.  
  19. #define INCLUDE_COMMON    /* include common code in helpcom.h */
  20.  
  21.  
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #ifndef XFRACT
  25. #include <io.h>
  26. #include <dos.h>
  27. #endif
  28. #include <fcntl.h>
  29. #include <string.h>
  30. #include <time.h>
  31. #include <assert.h>
  32. #include <sys/types.h>
  33. #include <sys/stat.h>
  34. #ifdef XFRACT
  35. #include <unistd.h>
  36. #endif
  37. #include "fractint.h"
  38. #include "helpcom.h"
  39. #include "helpdefs.h"
  40. #include "prototyp.h"
  41.  
  42.  
  43. #define MAX_HIST       16         /* number of pages we'll remember */
  44.  
  45. #define ALT_F1         1104
  46. #define BACK_TAB     1015
  47. #define BACKSPACE        8
  48.  
  49. #define ACTION_CALL        0         /* values returned by help_topic() */
  50. #define ACTION_PREV        1
  51. #define ACTION_PREV2        2         /* special - go back two topics */
  52. #define ACTION_INDEX        3
  53. #define ACTION_QUIT        4
  54.  
  55. #define F_HIST            (1<<0)   /* flags for help_topic() */
  56. #define F_INDEX         (1<<1)
  57.  
  58. #define MAX_PAGE_SIZE        (80*25)  /* no page of text may be larger */
  59.  
  60. #define TEXT_START_ROW        2         /* start print the help text here */
  61.  
  62.  
  63. typedef struct
  64.    {
  65.    BYTE r, c;
  66.    int         width;
  67.    unsigned     offset;
  68.    int         topic_num;
  69.    unsigned     topic_off;
  70.    } LINK;
  71.  
  72.  
  73. typedef struct
  74.    {
  75.    int        topic_num;
  76.    unsigned topic_off;
  77.    } LABEL;
  78.  
  79.  
  80. typedef struct
  81.    {
  82.    unsigned     offset;
  83.    unsigned     len;
  84.    int         margin;
  85.    } PAGE;
  86.  
  87.  
  88. typedef struct
  89.    {
  90.    int        topic_num;
  91.    unsigned topic_off;
  92.    int        link;
  93.    } HIST;
  94.  
  95.  
  96. struct help_sig_info
  97.    {
  98.    unsigned long sig;
  99.    int         version;
  100.    unsigned long base;       /* only if added to fractint.exe */
  101.    } ;
  102.  
  103.  
  104. void print_document(char *outfname, int (*msg_func)(int,int), int save_extraseg );
  105. static int print_doc_msg_func(int pnum, int num_pages);
  106.  
  107.  
  108.  
  109. void help_overlay(void) { }
  110.  
  111.  
  112.  
  113. /* stuff from fractint */
  114.  
  115. extern int  lookatmouse;
  116. extern long timer_start;
  117. extern int  helpmode;
  118. extern int  text_type;     /* 0=real color text, 1=640x200x2, 2=??mono?? */
  119. extern int  textcbase;
  120. extern int  textrbase;
  121. extern int  extraseg;
  122. extern int  release;
  123.  
  124. int  putstringcenter (int row, int col, int width, int attr, char far *msg);
  125. void helptitle         (void);
  126. void stackscreen     (void);
  127. void unstackscreen   (void);
  128. void findpath         (char *filename, char *path);
  129.  
  130.  
  131. static int          help_file = -1; /* help file handle */
  132. static long          base_off;       /* offset to help info in help file */
  133. static int          max_links;      /* max # of links in any page */
  134. static int          max_pages;      /* max # of pages in any topic */
  135. static int          num_label;      /* number of labels */
  136. static int          num_topic;      /* number of topics */
  137. static int          curr_hist = 0;  /* current pos in history */
  138.  
  139. /* these items alloc'ed in init_help... */
  140.  
  141. static long     far *topic_offset;       /* 4*num_topic */
  142. static LABEL     far *label;           /* 4*num_label */
  143. static HIST     far *hist;           /* 6*MAX_HIST (96 bytes) */
  144.  
  145. /* these items alloc'ed only while help is active... */
  146.  
  147. static char      far *buffer;         /* MAX_PAGE_SIZE (2048 bytes) */
  148. static LINK      far *link_table;     /* 10*max_links */
  149. static PAGE      far *page_table;     /* 4*max_pages  */
  150.  
  151.  
  152. static void help_seek(long pos)
  153.    {
  154.    lseek(help_file, base_off+pos, SEEK_SET);
  155.    }
  156.  
  157.  
  158. static void displayc(int row, int col, int color, int ch)
  159.    {
  160. #ifndef XFRACT
  161.    static char *s = "?";
  162. #else
  163.    static char s[] = "?";
  164. #endif
  165.  
  166.    if (text_type == 1)     /* if 640x200x2 mode */
  167.       {
  168.       /*
  169.        * This is REALLY ugly, but it works.  Non-current links (ones that
  170.        * would be bold if 640x200 supported it) are in upper-case and the
  171.        * current item is inversed.
  172.        *
  173.        */
  174.  
  175.       if (color & INVERSE)
  176.      color = (signed int)INVERSE;
  177.       else if (color & BRIGHT)
  178.      {
  179.      color = 0;   /* normal */
  180.      if (ch>='a' && ch<='z')
  181.         ch += 'A' - 'a';
  182.      }
  183.       else
  184.      color = 0;   /* normal */
  185.       }
  186.  
  187.    s[0] = ch;
  188.    putstring(row, col, color, s);
  189.    }
  190.  
  191.  
  192. static void display_text(int row, int col, int color, char far *text, unsigned len)
  193.    {
  194.    while (len-- > 0)
  195.       {
  196.       if (*text == CMD_LITERAL)
  197.      {
  198.      ++text;
  199.      --len;
  200.      }
  201.       displayc(row, col++, color, *text++);
  202.       }
  203.    }
  204.  
  205.  
  206. static void display_parse_text(char far *text, unsigned len, int start_margin, int *num_link, LINK far *link)
  207.    {
  208.    char far  *curr;
  209.    int          row, col;
  210.    int          tok;
  211.    int          size,
  212.           width;
  213.  
  214.    textcbase = SCREEN_INDENT;
  215.    textrbase = TEXT_START_ROW;
  216.  
  217.    curr = text;
  218.    row = 0;
  219.    col = 0;
  220.  
  221.    size = width = 0;
  222.  
  223.    if (start_margin >= 0)
  224.       tok = TOK_PARA;
  225.    else
  226.       tok = -1;
  227.  
  228.    while ( 1 )
  229.       {
  230.       switch ( tok )
  231.      {
  232.      case TOK_PARA:
  233.         {
  234.         int indent,
  235.         margin;
  236.  
  237.         if (size > 0)
  238.            {
  239.            ++curr;
  240.            indent = *curr++;
  241.            margin = *curr++;
  242.            len  -= 3;
  243.            }
  244.         else
  245.            {
  246.            indent = start_margin;
  247.            margin = start_margin;
  248.            }
  249.  
  250.         col = indent;
  251.  
  252.         while (1)
  253.            {
  254.            tok = find_token_length(ONLINE, curr, len, &size, &width);
  255.  
  256.            if (tok == TOK_DONE || tok == TOK_NL || tok == TOK_FF )
  257.           break;
  258.  
  259.            if (tok == TOK_PARA)
  260.           {
  261.           col = 0;   /* fake a new-line */
  262.           row++;
  263.           break;
  264.           }
  265.  
  266.            if (tok == TOK_XONLINE || tok == TOK_XDOC)
  267.           {
  268.           curr += size;
  269.           len  -= size;
  270.           continue;
  271.           }
  272.  
  273.            /* now tok is TOK_SPACE or TOK_LINK or TOK_WORD */
  274.  
  275.            if (col+width > SCREEN_WIDTH)
  276.           {         /* go to next line... */
  277.           col = margin;
  278.           ++row;
  279.  
  280.           if ( tok == TOK_SPACE )
  281.              width = 0;   /* skip spaces at start of a line */
  282.           }
  283.  
  284.            if (tok == TOK_LINK)
  285.           {
  286.           display_text(row, col, C_HELP_LINK, curr+1+3*sizeof(int), width);
  287.           if (num_link != NULL)
  288.              {
  289.              link[*num_link].r           = row;
  290.              link[*num_link].c           = col;
  291.                      link[*num_link].topic_num = getint(curr+1);
  292.                      link[*num_link].topic_off = getint(curr+1+sizeof(int));
  293.                      link[*num_link].offset    = (unsigned) ((curr+1+3*sizeof(int)) - text);
  294.              link[*num_link].width     = width;
  295.              ++(*num_link);
  296.              }
  297.           }
  298.            else if (tok == TOK_WORD )
  299.           display_text(row, col, C_HELP_BODY, curr, width);
  300.  
  301.            col += width;
  302.            curr += size;
  303.            len -= size;
  304.            }
  305.  
  306.         width = size = 0;
  307.         break;
  308.         }
  309.  
  310.      case TOK_CENTER:
  311.         col = find_line_width(ONLINE, curr, len);
  312.         col = (SCREEN_WIDTH-col)/2;
  313.         if (col < 0)
  314.            col = 0;
  315.         break;
  316.  
  317.      case TOK_NL:
  318.         col = 0;
  319.         ++row;
  320.         break;
  321.  
  322.      case TOK_LINK:
  323.             display_text(row, col, C_HELP_LINK, curr+1+3*sizeof(int), width);
  324.         if (num_link != NULL)
  325.            {
  326.            link[*num_link].r     = row;
  327.            link[*num_link].c     = col;
  328.                link[*num_link].topic_num = getint(curr+1);
  329.                link[*num_link].topic_off = getint(curr+1+sizeof(int));
  330.                link[*num_link].offset    = (unsigned) ((curr+1+3*sizeof(int)) - text);
  331.            link[*num_link].width     = width;
  332.            ++(*num_link);
  333.            }
  334.         break;
  335.  
  336.      case TOK_XONLINE:  /* skip */
  337.      case TOK_FF:        /* ignore */
  338.      case TOK_XDOC:     /* ignore */
  339.      case TOK_DONE:
  340.      case TOK_SPACE:
  341.         break;
  342.  
  343.      case TOK_WORD:
  344.         display_text(row, col, C_HELP_BODY, curr, width);
  345.         break;
  346.      } /* switch */
  347.  
  348.       curr += size;
  349.       len  -= size;
  350.       col  += width;
  351.  
  352.       if (len == 0)
  353.      break;
  354.  
  355.       tok = find_token_length(ONLINE, curr, len, &size, &width);
  356.       } /* while */
  357.  
  358.    textcbase = 0;
  359.    textrbase = 0;
  360.    }
  361.  
  362.  
  363. static void color_link(LINK far *link, int color)
  364.    {
  365.    textcbase = SCREEN_INDENT;
  366.    textrbase = TEXT_START_ROW;
  367.  
  368.    if (text_type == 1)     /* if 640x200x2 mode */
  369.       display_text(link->r, link->c, color, buffer+link->offset, link->width);
  370.    else
  371.       setattr(link->r, link->c, color, link->width);
  372.  
  373.    textcbase = 0;
  374.    textrbase = 0;
  375.    }
  376.  
  377.  
  378.  
  379. /* #define PUT_KEY(name, descrip) putstring(-1,-1,C_HELP_INSTR_KEYS,name), putstring(-1,-1,C_HELP_INSTR," "descrip"  ") */
  380. #ifndef XFRACT
  381. #define PUT_KEY(name, descrip) putstring(-1,-1,C_HELP_INSTR,name); putstring(-1,-1,C_HELP_INSTR,":"descrip"  ")
  382. #else
  383. #define PUT_KEY(name, descrip) putstring(-1,-1,C_HELP_INSTR,name);\
  384. putstring(-1,-1,C_HELP_INSTR,":");\
  385. putstring(-1,-1,C_HELP_INSTR,descrip);\
  386. putstring(-1,-1,C_HELP_INSTR,"  ")
  387. #endif
  388.  
  389.  
  390. static void helpinstr(void)
  391.    {
  392.    int ctr;
  393.  
  394.    for (ctr=0; ctr<80; ctr++)
  395.      putstring(24, ctr, C_HELP_INSTR, " ");
  396.  
  397.    movecursor(24, 1);
  398.    PUT_KEY("F1",               "Index");
  399. #ifndef XFRACT
  400.    PUT_KEY("\030\031\033\032", "Select");
  401. #else
  402.    PUT_KEY("K J H L", "Select");
  403. #endif
  404.    PUT_KEY("Enter",            "Go to");
  405.    PUT_KEY("Backspace",        "Last topic");
  406.    PUT_KEY("Escape",           "Exit help");
  407.    }
  408.  
  409.  
  410. static void printinstr(void)
  411.    {
  412.    int ctr;
  413.  
  414.    for (ctr=0; ctr<80; ctr++)
  415.      putstring(24, ctr, C_HELP_INSTR, " ");
  416.  
  417.    movecursor(24, 1);
  418.    PUT_KEY("Escape", "Abort");
  419.    }
  420.  
  421.  
  422. #undef PUT_KEY
  423.  
  424.  
  425. static void display_page(char far *title, char far *text, unsigned text_len, int page, int num_pages, int start_margin, int *num_link, LINK far *link)
  426.    {
  427.    char temp[9];
  428.  
  429.    helptitle();
  430.    helpinstr();
  431.    setattr(2, 0, C_HELP_BODY, 80*22);
  432.    putstringcenter(1, 0, 80, C_HELP_HDG, title);
  433.    sprintf(temp, "%2d of %d", page+1, num_pages);
  434. #ifndef XFRACT
  435.    putstring(1, 79-(6 + ((num_pages>=10)?2:1)), C_HELP_INSTR, temp);
  436. #else
  437.    /* Some systems (Ultrix) mess up if you write to column 80 */
  438.    putstring(1, 78-(6 + ((num_pages>=10)?2:1)), C_HELP_INSTR, temp);
  439. #endif
  440.  
  441.    if (text != NULL)
  442.       display_parse_text(text, text_len, start_margin, num_link, link);
  443.  
  444.    movecursor(25, 80);     /* hide cursor */
  445.    }
  446.  
  447.  
  448.  
  449. /*
  450.  * int overlap(int a, int a2, int b, int b2);
  451.  *
  452.  * If a, a2, b, and b2 are points on a line, this function returns the
  453.  * distance of intersection between a-->a2 and b-->b2.    If there is no
  454.  * intersection between the lines this function will return a negative number
  455.  * representing the distance between the two lines.
  456.  *
  457.  * There are six possible cases of intersection between the lines:
  458.  *
  459.  *            a              a2
  460.  *            |              |
  461.  *     b     b2    |              |       b     b2
  462.  *     |---(1)---|    |              |       |---(2)---|
  463.  *            |              |
  464.  *        b    |     b2      b       |      b2
  465.  *        |------(3)----|       |------(4)-----|
  466.  *            |              |
  467.  *         b    |              |   b2
  468.  *         |------+--------(5)----------+---|
  469.  *            |              |
  470.  *            |     b       b2      |
  471.  *            |     |--(6)--|       |
  472.  *            |              |
  473.  *            |              |
  474.  *
  475.  */
  476.  
  477.  
  478. static int overlap(int a, int a2, int b, int b2)
  479.    {
  480.    if ( b < a )
  481.       {
  482.       if ( b2 >= a2 )
  483.      return ( a2 - a );           /* case (5) */
  484.  
  485.       return ( b2 - a );           /* case (1), case (3) */
  486.       }
  487.  
  488.    if ( b2 <= a2 )
  489.       return ( b2 - b );           /* case (6) */
  490.  
  491.    return ( a2 - b );               /* case (2), case (4) */
  492.    }
  493.  
  494.  
  495. static int dist(int a, int b)
  496.    {
  497.    int t = a - b;
  498.  
  499.    return (abs(t));
  500.    }
  501.  
  502.  
  503. #ifdef __TURBOC__
  504. #   pragma warn -def /* turn off "Possible use before definition" warning */
  505. #endif
  506.  
  507.  
  508.  
  509.  
  510. static int find_link_updown(LINK far *link, int num_link, int curr_link, int up)
  511.    {
  512.    int         ctr,
  513.          curr_c2,
  514.          best_overlap,
  515.          temp_overlap;
  516.    LINK far *curr,
  517.     far *temp,
  518.     far *best;
  519.    int         temp_dist;
  520.  
  521.    curr    = &link[curr_link];
  522.    best    = NULL;
  523.    curr_c2 = curr->c + curr->width - 1;
  524.  
  525.    for (ctr=0, temp=link; ctr<num_link; ctr++, temp++)
  526.       {
  527.       if ( ctr != curr_link &&
  528.        ( (up && temp->r < curr->r) || (!up && temp->r > curr->r) ) )
  529.      {
  530.      temp_overlap = overlap(curr->c, curr_c2, temp->c, temp->c+temp->width-1);
  531.      /* if >= 3 lines between, prioritize on vertical distance: */
  532.      if ((temp_dist = dist(temp->r, curr->r)) >= 4)
  533.         temp_overlap -= temp_dist * 100;
  534.  
  535.      if (best != NULL)
  536.         {
  537.         if ( best_overlap >= 0 && temp_overlap >= 0 )
  538.            {     /* if they're both under curr set to closest in y dir */
  539.            if ( dist(best->r, curr->r) > temp_dist )
  540.           best = NULL;
  541.            }
  542.         else
  543.            {
  544.            if ( best_overlap < temp_overlap )
  545.           best = NULL;
  546.            }
  547.         }
  548.  
  549.      if (best == NULL)
  550.         {
  551.         best = temp;
  552.         best_overlap = temp_overlap;
  553.         }
  554.      }
  555.       }
  556.  
  557.    return ( (best==NULL) ? -1 : (int)(best-link) );
  558.    }
  559.  
  560.  
  561. static int find_link_leftright(LINK far *link, int num_link, int curr_link, int left)
  562.    {
  563.    int         ctr,
  564.          curr_c2,
  565.          best_c2,
  566.          temp_c2,
  567.          best_dist,
  568.          temp_dist;
  569.    LINK far *curr,
  570.     far *temp,
  571.     far *best;
  572.  
  573.    curr    = &link[curr_link];
  574.    best    = NULL;
  575.    curr_c2 = curr->c + curr->width - 1;
  576.  
  577.    for (ctr=0, temp=link; ctr<num_link; ctr++, temp++)
  578.       {
  579.       temp_c2 = temp->c + temp->width - 1;
  580.  
  581.       if ( ctr != curr_link &&
  582.        ( (left && temp_c2 < curr->c) || (!left && temp->c > curr_c2) ) )
  583.      {
  584.      temp_dist = dist(curr->r, temp->r);
  585.  
  586.      if (best != NULL)
  587.         {
  588.         if ( best_dist == 0 && temp_dist == 0 )  /* if both on curr's line... */
  589.            {
  590.            if ( (  left && dist(curr->c, best_c2) > dist(curr->c, temp_c2) ) ||
  591.             ( !left && dist(curr_c2, best->c) > dist(curr_c2, temp->c) ) )
  592.           best = NULL;
  593.            }
  594.         else
  595.            {
  596.            if ( best_dist >= temp_dist )   /* if temp is closer... */
  597.           best = NULL;
  598.            }
  599.         } /* if (best...) */
  600.  
  601.      if (best == NULL)
  602.         {
  603.         best      = temp;
  604.         best_dist = temp_dist;
  605.         best_c2   = temp_c2;
  606.         }
  607.      }
  608.       } /* for */
  609.  
  610.    return ( (best==NULL) ? -1 : (int)(best-link) );
  611.    }
  612.  
  613.  
  614. #ifdef __TURBOC__
  615. #   pragma warn .def   /* back to default */
  616. #   pragma warn -par   /* now turn off "Parameter not used" warning */
  617. #endif
  618.  
  619.  
  620. static int find_link_key(LINK far *link, int num_link, int curr_link, int key)
  621.    {
  622.    switch (key)
  623.       {
  624.       case TAB:      return ( (curr_link>=num_link-1) ? -1 : curr_link+1 );
  625.       case BACK_TAB: return ( (curr_link<=0)          ? -1 : curr_link-1 );
  626.       default:         assert(0);  return (-1);
  627.       }
  628.    }
  629.  
  630.  
  631. #ifdef __TURBOC__
  632. #   pragma warn .par /* back to default */
  633. #endif
  634.  
  635.  
  636. static int do_move_link(LINK far *link, int num_link, int *curr, int (*f)(LINK far *,int,int,int), int val)
  637.    {
  638.    int t;
  639.  
  640.    if (num_link > 1)
  641.       {
  642.       if ( f == NULL )
  643.      t = val;
  644.       else
  645.      t = (*f)(link, num_link, *curr, val);
  646.  
  647.       if ( t >= 0 && t != *curr )
  648.      {
  649.      color_link(&link[*curr], C_HELP_LINK);
  650.      *curr = t;
  651.      color_link(&link[*curr], C_HELP_CURLINK);
  652.      return (1);
  653.      }
  654.       }
  655.  
  656.    return (0);
  657.    }
  658.  
  659.  
  660. static int help_topic(HIST *curr, HIST *next, int flags)
  661.    {
  662.    int         len;
  663.    int         key;
  664.    int         num_pages;
  665.    int         num_link;
  666.    int         page;
  667.    int         curr_link;
  668.    char      title[81];
  669.    long      where;
  670.    int         draw_page;
  671.    int         action;
  672.    BYTE ch;
  673.  
  674.    where     = topic_offset[curr->topic_num]+sizeof(int); /* to skip flags */
  675.    curr_link = curr->link;
  676.  
  677.    help_seek(where);
  678.  
  679.    read(help_file, (char *)&num_pages, sizeof(int));
  680.    assert(num_pages>0 && num_pages<=max_pages);
  681.  
  682.    farread(help_file, (char far *)page_table, 3*sizeof(int)*num_pages);
  683.  
  684.    read(help_file, &ch, 1);
  685.    len = ch;
  686.    assert(len<81);
  687.    read(help_file, (char *)title, len);
  688.    title[len] = '\0';
  689.  
  690.    where += sizeof(int) + num_pages*3*sizeof(int) + 1 + len + sizeof(int);
  691.  
  692.    for(page=0; page<num_pages; page++)
  693.       if (curr->topic_off >= page_table[page].offset &&
  694.       curr->topic_off <  page_table[page].offset+page_table[page].len )
  695.      break;
  696.  
  697.    assert(page < num_pages);
  698.  
  699.    action = -1;
  700.    draw_page = 2;
  701.  
  702.    do
  703.       {
  704.       if (draw_page)
  705.      {
  706.      help_seek(where+page_table[page].offset);
  707.      farread(help_file, buffer, page_table[page].len);
  708.  
  709.      num_link = 0;
  710.      display_page(title, buffer, page_table[page].len, page, num_pages,
  711.               page_table[page].margin, &num_link, link_table);
  712.  
  713.      if (draw_page==2)
  714.         {
  715.         assert(num_link<=0 || (curr_link>=0 && curr_link<num_link));
  716.         }
  717.      else if (draw_page==3)
  718.         curr_link = num_link - 1;
  719.      else
  720.         curr_link = 0;
  721.  
  722.      if (num_link > 0)
  723.         color_link(&link_table[curr_link], C_HELP_CURLINK);
  724.  
  725.      draw_page = 0;
  726.      }
  727.  
  728.       key = getakey();
  729.  
  730.       switch(key)
  731.      {
  732.      case PAGE_DOWN:
  733.         if (page<num_pages-1)
  734.            {
  735.            page++;
  736.            draw_page = 1;
  737.            }
  738.         break;
  739.  
  740.      case PAGE_UP:
  741.         if (page>0)
  742.            {
  743.            page--;
  744.            draw_page = 1;
  745.            }
  746.         break;
  747.  
  748.      case HOME:
  749.         if ( page != 0 )
  750.            {
  751.            page = 0;
  752.            draw_page = 1;
  753.            }
  754.         else
  755.            do_move_link(link_table, num_link, &curr_link, NULL, 0);
  756.         break;
  757.  
  758.      case END:
  759.         if ( page != num_pages-1 )
  760.            {
  761.            page = num_pages-1;
  762.            draw_page = 3;
  763.            }
  764.         else
  765.            do_move_link(link_table, num_link, &curr_link, NULL, num_link-1);
  766.         break;
  767.  
  768.      case TAB:
  769.         if ( !do_move_link(link_table, num_link, &curr_link, find_link_key, key) &&
  770.          page<num_pages-1 )
  771.            {
  772.            ++page;
  773.            draw_page = 1;
  774.            }
  775.         break;
  776.  
  777.      case BACK_TAB:
  778.         if ( !do_move_link(link_table, num_link, &curr_link, find_link_key, key) &&
  779.          page>0 )
  780.            {
  781.            --page;
  782.            draw_page = 3;
  783.            }
  784.         break;
  785.  
  786.      case DOWN_ARROW:
  787.         if ( !do_move_link(link_table, num_link, &curr_link, find_link_updown, 0) &&
  788.          page<num_pages-1 )
  789.            {
  790.            ++page;
  791.            draw_page = 1;
  792.            }
  793.         break;
  794.  
  795.      case UP_ARROW:
  796.         if ( !do_move_link(link_table, num_link, &curr_link, find_link_updown, 1) &&
  797.          page>0 )
  798.            {
  799.            --page;
  800.            draw_page = 3;
  801.            }
  802.         break;
  803.  
  804.      case LEFT_ARROW:
  805.         do_move_link(link_table, num_link, &curr_link, find_link_leftright, 1);
  806.         break;
  807.  
  808.      case RIGHT_ARROW:
  809.         do_move_link(link_table, num_link, &curr_link, find_link_leftright, 0);
  810.         break;
  811.  
  812.      case ESC:       /* exit help */
  813.         action = ACTION_QUIT;
  814.         break;
  815.  
  816.      case BACKSPACE:   /* prev topic */
  817.      case ALT_F1:
  818.         if (flags & F_HIST)
  819.            action = ACTION_PREV;
  820.         break;
  821.  
  822.      case F1:    /* help index */
  823.         if (!(flags & F_INDEX))
  824.            action = ACTION_INDEX;
  825.         break;
  826.  
  827.      case ENTER:
  828.      case ENTER_2:
  829.         if (num_link > 0)
  830.            {
  831.            next->topic_num = link_table[curr_link].topic_num;
  832.            next->topic_off = link_table[curr_link].topic_off;
  833.            action = ACTION_CALL;
  834.            }
  835.         break;
  836.      } /* switch */
  837.       }
  838.    while ( action == -1 );
  839.  
  840.    curr->topic_off = page_table[page].offset;
  841.    curr->link       = curr_link;
  842.  
  843.    return (action);
  844.    }
  845.  
  846.  
  847. int help(int action)
  848.    {
  849.    static char far unknowntopic_msg[] = "Unknown Help Topic";
  850.    HIST      curr;
  851.    int         oldlookatmouse;
  852.    int         oldhelpmode;
  853.    int         flags;
  854.    HIST      next;
  855.  
  856.    ENTER_OVLY(OVLY_HELP);
  857.  
  858.    if (helpmode == -1)     /* is help disabled? */
  859.       {
  860.       EXIT_OVLY;
  861.       return (0);
  862.       }
  863.  
  864.    if (help_file == -1)
  865.       {
  866.       buzzer(2);
  867.       EXIT_OVLY;
  868.       return (0);
  869.       }
  870.  
  871.    buffer = farmemalloc((long)MAX_PAGE_SIZE + sizeof(LINK)*max_links +
  872.             sizeof(PAGE)*max_pages);
  873.  
  874.    if (buffer == NULL)
  875.       {
  876.       buzzer(2);
  877.       EXIT_OVLY;
  878.       return (0);
  879.       }
  880.  
  881.    link_table = (LINK far *)(&buffer[MAX_PAGE_SIZE]);
  882.    page_table = (PAGE far *)(&link_table[max_links]);
  883.  
  884.    oldlookatmouse = lookatmouse;
  885.    lookatmouse = 0;
  886.    timer_start -= clock_ticks();
  887.    stackscreen();
  888.  
  889.    if (helpmode >= 0)
  890.       {
  891.       next.topic_num = label[helpmode].topic_num;
  892.       next.topic_off = label[helpmode].topic_off;
  893.       }
  894.    else
  895.       {
  896.       next.topic_num = helpmode;
  897.       next.topic_off = 0;
  898.       }
  899.  
  900.    oldhelpmode = helpmode;
  901.  
  902.    if (curr_hist <= 0)
  903.       action = ACTION_CALL;  /* make sure it isn't ACTION_PREV! */
  904.  
  905.    do
  906.       {
  907.       switch(action)
  908.      {
  909.      case ACTION_PREV2:
  910.         if (curr_hist > 0)
  911.            curr = hist[--curr_hist];
  912.  
  913.         /* fall-through */
  914.  
  915.      case ACTION_PREV:
  916.         if (curr_hist > 0)
  917.            curr = hist[--curr_hist];
  918.         break;
  919.  
  920.      case ACTION_QUIT:
  921.         break;
  922.  
  923.      case ACTION_INDEX:
  924.         next.topic_num = label[HELP_INDEX].topic_num;
  925.         next.topic_off = label[HELP_INDEX].topic_off;
  926.  
  927.         /* fall-through */
  928.  
  929.      case ACTION_CALL:
  930.         curr = next;
  931.         curr.link = 0;
  932.         break;
  933.      } /* switch */
  934.  
  935.       flags = 0;
  936.       if (curr.topic_num == label[HELP_INDEX].topic_num)
  937.      flags |= F_INDEX;
  938.       if (curr_hist > 0)
  939.      flags |= F_HIST;
  940.  
  941.       if ( curr.topic_num >= 0 )
  942.      action = help_topic(&curr, &next, flags);
  943.       else
  944.      {
  945.      if ( curr.topic_num == -100 )
  946.         {
  947.         print_document("FRACTINT.DOC", print_doc_msg_func, 1);
  948.         action = ACTION_PREV2;
  949.         }
  950.  
  951.      else if ( curr.topic_num == -101 )
  952.         action = ACTION_PREV2;
  953.  
  954.      else
  955.         {
  956.         display_page(unknowntopic_msg, NULL, 0, 0, 1, 0, NULL, NULL);
  957.         action = -1;
  958.         while (action == -1)
  959.            {
  960.            switch (getakey())
  961.           {
  962.           case ESC:     action = ACTION_QUIT;    break;
  963.           case ALT_F1:     action = ACTION_PREV;    break;
  964.           case F1:     action = ACTION_INDEX; break;
  965.           } /* switch */
  966.            } /* while */
  967.         }
  968.      } /* else */
  969.  
  970.       if ( action != ACTION_PREV && action != ACTION_PREV2 )
  971.      {
  972.      if (curr_hist >= MAX_HIST)
  973.         {
  974.         int ctr;
  975.  
  976.         for (ctr=0; ctr<MAX_HIST-1; ctr++)
  977.            hist[ctr] = hist[ctr+1];
  978.  
  979.         curr_hist = MAX_HIST-1;
  980.         }
  981.      hist[curr_hist++] = curr;
  982.      }
  983.       }
  984.    while (action != ACTION_QUIT);
  985.  
  986.    farmemfree((BYTE far *)buffer);
  987.  
  988.    unstackscreen();
  989.    lookatmouse = oldlookatmouse;
  990.    helpmode = oldhelpmode;
  991.    timer_start += clock_ticks();
  992.  
  993.    EXIT_OVLY;
  994.    return(0);
  995.    }
  996.  
  997.  
  998.  
  999. static int dos_version(void)
  1000.    {
  1001. #ifndef XFRACT
  1002.    union REGS r;
  1003.  
  1004.    r.x.ax = 0x3000;
  1005.    intdos(&r, &r);
  1006.  
  1007.    return (r.h.al*100 + r.h.ah);
  1008. #else
  1009.    return 0;
  1010. #endif
  1011.    }
  1012.  
  1013.  
  1014. static int exe_path(char *filename, char *path)
  1015.    {
  1016. #ifndef XFRACT
  1017.    char *ptr;
  1018.  
  1019.    if (dos_version() >= 300)  /* DOS version 3.00+ ? */
  1020.       {
  1021. #ifdef __TURBOC__
  1022.       strcpy(path, _argv[0]);
  1023. #else  /* assume MSC */
  1024.       extern char **__argv;
  1025.       strcpy(path, __argv[0]);     /* note: __argv may be undocumented in MSC */
  1026. #endif
  1027.  
  1028.       ptr = strrchr(path, SLASHC);
  1029.       if (ptr == NULL)
  1030.      ptr = path;
  1031.       else
  1032.      ++ptr;
  1033.       strcpy(ptr, filename);
  1034.       return (1);
  1035.       }
  1036.  
  1037.    return (0);
  1038. #else
  1039.    strcpy(path,SRCDIR);
  1040.    strcat(path,"/");
  1041.    strcat(path,filename);
  1042.    return 1;
  1043. #endif
  1044.    }
  1045.  
  1046.  
  1047. static int find_file(char *filename, char *path)
  1048.    {
  1049.    int handle;
  1050.  
  1051.    if ( exe_path(filename, path) )
  1052.       if ( (handle=open(path, O_RDONLY)) != -1)
  1053.      {
  1054.      close(handle);
  1055.      return (1);
  1056.      }
  1057.  
  1058.    findpath(filename,path);
  1059.    return ( (path[0]) ? 1 : 0);
  1060.    }
  1061.  
  1062.  
  1063. static int _read_help_topic(int topic, int off, int len, VOIDFARPTR buf)
  1064.    {
  1065.    static int  curr_topic = -1;
  1066.    static long curr_base;
  1067.    static int  curr_len;
  1068.    int           read_len;
  1069.  
  1070.    if ( topic != curr_topic )
  1071.       {
  1072.       int t;
  1073.       char ch;
  1074.  
  1075.       curr_topic = topic;
  1076.  
  1077.       curr_base = topic_offset[topic];
  1078.  
  1079.       curr_base += sizeof(int);            /* skip flags */
  1080.  
  1081.       help_seek(curr_base);
  1082.       read(help_file, (char *)&t, sizeof(int));    /* read num_pages */
  1083.       curr_base += sizeof(int) + t*3*sizeof(int); /* skip page info */
  1084.  
  1085.       if (t>0)
  1086.      help_seek(curr_base);
  1087.       read(help_file, &ch, 1);            /* read title_len */
  1088.       t = ch;
  1089.       curr_base += 1 + t;            /* skip title */
  1090.  
  1091.       if (t>0)
  1092.      help_seek(curr_base);
  1093.       read(help_file, (char *)&curr_len, sizeof(int)); /* read topic len */
  1094.       curr_base += sizeof(int);
  1095.       }
  1096.  
  1097.    read_len = (off+len > curr_len) ? curr_len - off : len;
  1098.  
  1099.    if (read_len > 0)
  1100.       {
  1101.       help_seek(curr_base + off);
  1102.       farread(help_file, (char far *)buf, read_len);
  1103.       }
  1104.  
  1105.    return ( curr_len - (off+len) );
  1106.    }
  1107.  
  1108.  
  1109. int read_help_topic(int label_num, int off, int len, VOIDFARPTR buf)
  1110.    /*
  1111.     * reads text from a help topic.  Returns number of bytes from (off+len)
  1112.     * to end of topic.    On "EOF" returns a negative number representing
  1113.     * number of bytes not read.
  1114.     */
  1115.    {
  1116.    int ret;
  1117.  
  1118.    ENTER_OVLY(OVLY_HELP);
  1119.  
  1120.    ret = _read_help_topic(label[label_num].topic_num,
  1121.               label[label_num].topic_off + off, len, buf);
  1122.  
  1123.    EXIT_OVLY;
  1124.  
  1125.    return ( ret );
  1126.    }
  1127.  
  1128.  
  1129. #define PRINT_BUFFER_SIZE  (32767)     /* max. size of help topic in doc. */
  1130. #define TEMP_FILE_NAME       "HELP.$$$"    /* temp file for storing extraseg  */
  1131.                      /*    while printing document        */
  1132. #define MAX_NUM_TOPIC_SEC  (10)      /* max. number of topics under any */
  1133.                      /*    single section (CONTENT)     */
  1134.  
  1135.  
  1136. typedef struct PRINT_DOC_INFO
  1137.    {
  1138.    int         cnum;        /* current CONTENT num */
  1139.    int         tnum;        /* current topic num */
  1140.  
  1141.    long      content_pos;   /* current CONTENT item offset in file */
  1142.    int         num_page;        /* total number of pages in document */
  1143.  
  1144.    int         num_contents,  /* total number of CONTENT entries */
  1145.          num_topic;     /* number of topics in current CONTENT */
  1146.  
  1147.    int         topic_num[MAX_NUM_TOPIC_SEC]; /* topic_num[] for current CONTENT entry */
  1148.  
  1149.    char far *buffer;        /* text buffer */
  1150.  
  1151.    char      id[81];        /* buffer to store id in */
  1152.    char      title[81];     /* buffer to store title in */
  1153.  
  1154. #ifndef XFRACT
  1155.    int     (*msg_func)(int pnum, int num_page);
  1156. #else
  1157.    int     (*msg_func)();
  1158.    int pnum;
  1159. #endif
  1160.  
  1161.    FILE     *file;        /* file to sent output to */
  1162.    int         margin;        /* indent text by this much */
  1163.    int         start_of_line; /* are we at the beginning of a line? */
  1164.    int         spaces;        /* number of spaces in a row */
  1165.    } PRINT_DOC_INFO;
  1166.  
  1167.  
  1168. void print_document(char *outfname, int (*msg_func)(int,int), int save_extraseg );
  1169.  
  1170.  
  1171. static void printerc(PRINT_DOC_INFO *info, int c, int n)
  1172.    {
  1173.    while ( n-- > 0 )
  1174.       {
  1175.       if (c==' ')
  1176.      ++info->spaces;
  1177.  
  1178.       else if (c=='\n' || c=='\f')
  1179.      {
  1180.      info->start_of_line = 1;
  1181.      info->spaces = 0;   /* strip spaces before a new-line */
  1182.      putc(c, info->file);
  1183.      }
  1184.  
  1185.       else
  1186.      {
  1187.      if (info->start_of_line)
  1188.         {
  1189.         info->spaces += info->margin;
  1190.         info->start_of_line = 0;
  1191.         }
  1192.  
  1193.      while (info->spaces > 0)
  1194.         {
  1195.         fputc(' ', info->file);
  1196.         --info->spaces;
  1197.         }
  1198.  
  1199.      fputc(c, info->file);
  1200.      }
  1201.       }
  1202.    }
  1203.  
  1204.  
  1205. static void printers(PRINT_DOC_INFO *info, char far *s, int n)
  1206.    {
  1207.    if (n > 0)
  1208.       {
  1209.       while ( n-- > 0 )
  1210.      printerc(info, *s++, 1);
  1211.       }
  1212.    else
  1213.       {
  1214.       while ( *s != '\0' )
  1215.      printerc(info, *s++, 1);
  1216.       }
  1217.    }
  1218.  
  1219.  
  1220. static int print_doc_get_info(int cmd, PD_INFO *pd, PRINT_DOC_INFO *info)
  1221.    {
  1222.    int t;
  1223.    BYTE ch;
  1224.  
  1225.    switch (cmd)
  1226.       {
  1227.       case PD_GET_CONTENT:
  1228.      if ( ++info->cnum >= info->num_contents )
  1229.         return (0);
  1230.  
  1231.      help_seek( info->content_pos );
  1232.  
  1233.          read(help_file, (char *)&t, sizeof(int));      /* read flags */
  1234.          info->content_pos += sizeof(int);
  1235.      pd->new_page = (t & 1) ? 1 : 0;
  1236.  
  1237.          read(help_file, &ch, 1);       /* read id len */
  1238.          t = ch;
  1239.      assert(t<80);
  1240.      read(help_file, (char *)info->id, t);    /* read the id */
  1241.      info->content_pos += 1 + t;
  1242.      info->id[t] = '\0';
  1243.  
  1244.          read(help_file, (char *)&ch, 1);       /* read title len */
  1245.          t = ch;
  1246.      assert(t<80);
  1247.      read(help_file, (char *)info->title, t); /* read the title */
  1248.      info->content_pos += 1 + t;
  1249.      info->title[t] = '\0';
  1250.  
  1251.          read(help_file, (char *)&ch, 1);       /* read num_topic */
  1252.          t = ch;
  1253.      assert(t<MAX_NUM_TOPIC_SEC);
  1254.          read(help_file, (char *)info->topic_num, t*sizeof(int));  /* read topic_num[] */
  1255.      info->num_topic = t;
  1256.          info->content_pos += 1 + t*sizeof(int);
  1257.  
  1258.      info->tnum = -1;
  1259.  
  1260.      pd->id = info->id;
  1261.      pd->title = info->title;
  1262.      return (1);
  1263.  
  1264.       case PD_GET_TOPIC:
  1265.      if ( ++info->tnum >= info->num_topic )
  1266.         return (0);
  1267.  
  1268.      t = _read_help_topic(info->topic_num[info->tnum], 0, PRINT_BUFFER_SIZE, info->buffer);
  1269.  
  1270.      assert(t <= 0);
  1271.  
  1272.      pd->curr = info->buffer;
  1273.      pd->len  = PRINT_BUFFER_SIZE + t;   /* same as ...SIZE - abs(t) */
  1274.      return (1);
  1275.  
  1276.       case PD_GET_LINK_PAGE:
  1277.          pd->i = getint(pd->s+sizeof(long));
  1278.      return ( (pd->i == -1) ? 0 : 1 );
  1279.  
  1280.       case PD_RELEASE_TOPIC:
  1281.      return (1);
  1282.  
  1283.       default:
  1284.      return (0);
  1285.       }
  1286.    }
  1287.  
  1288.  
  1289. static int print_doc_output(int cmd, PD_INFO *pd, PRINT_DOC_INFO *info)
  1290.    {
  1291.    switch (cmd)
  1292.       {
  1293.       case PD_HEADING:
  1294.      {
  1295.      char line[81];
  1296.      char buff[40];
  1297.      int  width = PAGE_WIDTH + PAGE_INDENT;
  1298.      int  keep_going;
  1299.  
  1300.      if ( info->msg_func != NULL )
  1301.         keep_going = (*info->msg_func)(pd->pnum, info->num_page);
  1302.      else
  1303.         keep_going = 1;
  1304.  
  1305.      info->margin = 0;
  1306.  
  1307.      memset(line, ' ', 81);
  1308.      sprintf(buff, "Fractint Version %d.%01d%c",release/100, (release%100)/10,
  1309.                 ( (release%10) ? '0'+(release%10) : ' ') );
  1310.      memmove(line + ( (width-strlen(buff)) / 2)-4, buff, strlen(buff));
  1311.  
  1312.      sprintf(buff, "Page %d", pd->pnum);
  1313.      memmove(line + (width - strlen(buff)), buff, strlen(buff));
  1314.  
  1315.      printerc(info, '\n', 1);
  1316.      printers(info, line, width);
  1317.      printerc(info, '\n', 2);
  1318.  
  1319.      info->margin = PAGE_INDENT;
  1320.  
  1321.      return ( keep_going );
  1322.      }
  1323.  
  1324.       case PD_FOOTING:
  1325.      info->margin = 0;
  1326.      printerc(info, '\f', 1);
  1327.      info->margin = PAGE_INDENT;
  1328.      return (1);
  1329.  
  1330.       case PD_PRINT:
  1331.      printers(info, pd->s, pd->i);
  1332.      return (1);
  1333.  
  1334.       case PD_PRINTN:
  1335.      printerc(info, *pd->s, pd->i);
  1336.      return (1);
  1337.  
  1338.       case PD_PRINT_SEC:
  1339.      info->margin = TITLE_INDENT;
  1340.      if (pd->id[0] != '\0')
  1341.         {
  1342.         printers(info, pd->id, 0);
  1343.         printerc(info, ' ', 1);
  1344.         }
  1345.      printers(info, pd->title, 0);
  1346.      printerc(info, '\n', 1);
  1347.      info->margin = PAGE_INDENT;
  1348.      return (1);
  1349.  
  1350.       case PD_START_SECTION:
  1351.       case PD_START_TOPIC:
  1352.       case PD_SET_SECTION_PAGE:
  1353.       case PD_SET_TOPIC_PAGE:
  1354.       case PD_PERIODIC:
  1355.      return (1);
  1356.  
  1357.       default:
  1358.      return (0);
  1359.       }
  1360.    }
  1361.  
  1362.  
  1363. static int print_doc_msg_func(int pnum, int num_pages)
  1364.    {
  1365.    char temp[10];
  1366.    int    key;
  1367.  
  1368.    if ( pnum == -1 )    /* successful completion */
  1369.       {
  1370.       buzzer(0);
  1371.       putstringcenter(7, 0, 80, C_HELP_LINK, "Done -- Press any key");
  1372.       getakey();
  1373.       return (0);
  1374.       }
  1375.  
  1376.    if ( pnum == -2 )   /* aborted */
  1377.       {
  1378.       buzzer(1);
  1379.       putstringcenter(7, 0, 80, C_HELP_LINK, "Aborted -- Press any key");
  1380.       getakey();
  1381.       return (0);
  1382.       }
  1383.  
  1384.    if (pnum == 0)   /* initialization */
  1385.       {
  1386.       helptitle();
  1387.       printinstr();
  1388.       setattr(2, 0, C_HELP_BODY, 80*22);
  1389.       putstringcenter(1, 0, 80, C_HELP_HDG, "Generating FRACTINT.DOC");
  1390.  
  1391.       putstring(7, 30, C_HELP_BODY, "Completed:");
  1392.  
  1393.       movecursor(25,80);   /* hide cursor */
  1394.       }
  1395.  
  1396.  
  1397.    sprintf(temp, "%d%%", (int)( (100.0 / num_pages) * pnum ) );
  1398.    putstring(7, 41, C_HELP_LINK, temp);
  1399.  
  1400.    while ( keypressed() )
  1401.       {
  1402.       key = getakey();
  1403.       if ( key == ESC )
  1404.      return (0);    /* user abort */
  1405.       }
  1406.  
  1407.    return (1);     /* AOK -- continue */
  1408.    }
  1409.  
  1410. int makedoc_msg_func(int pnum, int num_pages)
  1411.    {
  1412.    if (pnum >= 0)
  1413.       {
  1414.       printf("\rcompleted %d%%", (int)( (100.0 / num_pages) * pnum ) );
  1415.       return (1);
  1416.       }
  1417.    if ( pnum == -2 )
  1418.       printf("\n*** aborted");
  1419.    printf("\n");
  1420.    return (0);
  1421.    }
  1422.  
  1423.  
  1424.  
  1425. void print_document(char *outfname, int (*msg_func)(int,int), int save_extraseg )
  1426.    {
  1427.    static char far err_no_temp[]  = "Unable to create temporary file.\n";
  1428.    static char far err_no_out[]   = "Unable to create output file.\n";
  1429.    static char far err_badwrite[] = "Error writing temporary file.\n";
  1430.    static char far err_badread[]  = "Error reading temporary file.\nSystem may be corrupt!\nSave your image and re-start FRACTINT!\n";
  1431.  
  1432.    PRINT_DOC_INFO info;
  1433.    int          success;
  1434.    int          temp_file = -1;
  1435.    char      far *msg = NULL;
  1436.  
  1437.    ENTER_OVLY(OVLY_HELP);
  1438.  
  1439.    info.buffer = MK_FP(extraseg, 0);
  1440.  
  1441. /*   help_seek((long)sizeof(int)+sizeof(long));        Strange -- should be 8 -- CWM */
  1442.    help_seek(8L);                /* indeed it should - Bert */
  1443.    read(help_file, (char *)&info.num_contents, sizeof(int));
  1444.    read(help_file, (char *)&info.num_page, sizeof(int));
  1445.  
  1446.    info.cnum = info.tnum = -1;
  1447.    info.content_pos = sizeof(long)+4*sizeof(int) + num_topic*sizeof(long) + num_label*2*sizeof(int);
  1448.    info.msg_func = msg_func;
  1449.  
  1450.    if ( msg_func != NULL )
  1451.       msg_func(0, info.num_page);   /* initialize */
  1452.  
  1453.    if ( save_extraseg )
  1454.       {
  1455.       if ( (temp_file=open(TEMP_FILE_NAME, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, S_IREAD|S_IWRITE)) == -1 )
  1456.      {
  1457.      msg = err_no_temp;
  1458.      goto ErrorAbort;
  1459.      }
  1460.  
  1461.       if ( farwrite(temp_file, info.buffer, PRINT_BUFFER_SIZE) != PRINT_BUFFER_SIZE )
  1462.      {
  1463.      msg = err_badwrite;
  1464.      goto ErrorAbort;
  1465.      }
  1466.       }
  1467.  
  1468.    if ( (info.file = fopen(outfname, "wt")) == NULL )
  1469.       {
  1470.       msg = err_no_out;
  1471.       goto ErrorAbort;
  1472.       }
  1473.  
  1474.    info.margin = PAGE_INDENT;
  1475.    info.start_of_line = 1;
  1476.    info.spaces = 0;
  1477.  
  1478.    success = process_document((PD_FUNC)print_doc_get_info,
  1479.                   (PD_FUNC)print_doc_output,   &info);
  1480.    fclose(info.file);
  1481.  
  1482.    if ( save_extraseg )
  1483.       {
  1484.       if ( lseek(temp_file, 0L, SEEK_SET) != 0L )
  1485.      {
  1486.      msg = err_badread;
  1487.      goto ErrorAbort;
  1488.      }
  1489.  
  1490.       if ( farread(temp_file, info.buffer, PRINT_BUFFER_SIZE) != PRINT_BUFFER_SIZE )
  1491.      {
  1492.      msg = err_badread;
  1493.      goto ErrorAbort;
  1494.      }
  1495.       }
  1496.  
  1497. ErrorAbort:
  1498.    if (temp_file != -1)
  1499.       {
  1500.       close(temp_file);
  1501.       remove(TEMP_FILE_NAME);
  1502.       temp_file = -1;
  1503.       }
  1504.  
  1505.    if ( msg != NULL )
  1506.       {
  1507.       helptitle();
  1508.       stopmsg(1, msg);
  1509.       }
  1510.  
  1511.    else if ( msg_func != NULL )
  1512.       msg_func((success) ? -1 : -2, info.num_page );
  1513.  
  1514.    EXIT_OVLY;
  1515.    }
  1516.  
  1517.  
  1518. int init_help(void)
  1519.    {
  1520.    struct help_sig_info hs;
  1521.    char         path[81];
  1522.  
  1523.    ENTER_OVLY(OVLY_HELP);
  1524.  
  1525.    help_file = -1;
  1526.  
  1527. #ifndef XFRACT
  1528.    if (help_file == -1)        /* now look for help files in FRACTINT.EXE */
  1529.       {
  1530.       static char far err_no_open[]    = "Help system was unable to open FRACTINT.EXE!\n";
  1531.       static char far err_no_exe[]     = "Help system couldn't find FRACTINT.EXE!\n";
  1532.       static char far err_wrong_ver[]  = "Wrong help version in FRACTINT.EXE!\n";
  1533. /*
  1534.       static char far err_not_in_exe[] = "Help not found in FRACTINT.EXE!\n";
  1535. */
  1536.  
  1537.       if ( find_file("FRACTINT.EXE", path) )
  1538.      {
  1539.      if ( (help_file = open(path, O_RDONLY|O_BINARY)) != -1 )
  1540.         {
  1541.         long help_offset;
  1542.  
  1543.         for (help_offset = -((long)sizeof(hs)); help_offset >= -128L; help_offset--)
  1544.                {
  1545.            lseek(help_file, help_offset, SEEK_END);
  1546.            read(help_file, (char *)&hs, sizeof(hs));
  1547.            if (hs.sig == HELP_SIG)  break;
  1548.            }
  1549.  
  1550.         if ( hs.sig != HELP_SIG )
  1551.            {
  1552.            close(help_file);
  1553.            help_file = -1;
  1554.            /* (leave out the error message)
  1555.            stopmsg(1, err_not_in_exe);
  1556.            */
  1557.            }
  1558.  
  1559.         else
  1560.            {
  1561.            if ( hs.version != HELP_VERSION )
  1562.               {
  1563.               close(help_file);
  1564.               help_file = -1;
  1565.               stopmsg(1, err_wrong_ver);
  1566.               }
  1567.              else
  1568.               base_off = hs.base;
  1569.  
  1570.                }
  1571.         }
  1572.      else
  1573.         stopmsg(1, err_no_open);
  1574.      }
  1575.       else
  1576.      stopmsg(1, err_no_exe);
  1577.  
  1578.       }
  1579. #endif
  1580.  
  1581. if (help_file == -1)        /* look for FRACTINT.HLP */
  1582.    {
  1583.    if ( find_file("fractint.hlp", path) )
  1584.       {
  1585.       if ( (help_file = open(path, O_RDONLY|O_BINARY)) != -1 )
  1586.      {
  1587.          read(help_file, (char *)&hs, sizeof(long)+sizeof(int));
  1588.  
  1589.      if ( hs.sig != HELP_SIG )
  1590.         {
  1591.         static char far msg[] = {"Invalid help signature in FRACTINT.HLP!\n"};
  1592.         close(help_file);
  1593.         stopmsg(1, msg);
  1594.         }
  1595.  
  1596.      else if ( hs.version != HELP_VERSION )
  1597.         {
  1598.         static char far msg[] = {"Wrong help version in FRACTINT.HLP!\n"};
  1599.         close(help_file);
  1600.         stopmsg(1, msg);
  1601.         }
  1602.  
  1603.      else
  1604.         base_off = sizeof(long)+sizeof(int);
  1605.      }
  1606.       }
  1607.    }
  1608.  
  1609.    if (help_file == -1)        /* Can't find the help files anywhere! */
  1610.       {
  1611.       static char far msg[] =
  1612.      {"Help Files aren't in FRACTINT.EXE, and couldn't find FRACTINT.HLP!\n"};
  1613.       stopmsg(1, msg);
  1614.       }
  1615.  
  1616.    help_seek(0L);
  1617.  
  1618.    read(help_file, (char *)&max_pages, sizeof(int));
  1619.    read(help_file, (char *)&max_links, sizeof(int));
  1620.    read(help_file, (char *)&num_topic, sizeof(int));
  1621.    read(help_file, (char *)&num_label, sizeof(int));
  1622.    help_seek((long)6*sizeof(int));  /* skip num_contents and num_doc_pages */
  1623.  
  1624.    assert(max_pages > 0);
  1625.    assert(max_links >= 0);
  1626.    assert(num_topic > 0);
  1627.    assert(num_label > 0);
  1628.  
  1629.    /* allocate one big chunk for all three arrays */
  1630.  
  1631.    topic_offset = (long far *)farmemalloc(sizeof(long)*num_topic + 2L*sizeof(int)*num_label + sizeof(HIST)*MAX_HIST);
  1632.  
  1633.    if (topic_offset == NULL)
  1634.       {
  1635.       static char far err_no_mem[] = "Not enough memory for help system!\n";
  1636.       close(help_file);
  1637.       help_file = -1;
  1638.       stopmsg(1, err_no_mem);
  1639.  
  1640.       EXIT_OVLY;      /* JIC stopmsg continues for some reason? */
  1641.       return (-2);
  1642.       }
  1643.  
  1644.    /* split off the other arrays */
  1645.  
  1646.    label = (LABEL far *)(&topic_offset[num_topic]);
  1647.    hist  = (HIST far *)(&label[num_label]);
  1648.  
  1649.    /* read in the tables... */
  1650.  
  1651.    farread(help_file, topic_offset, num_topic*sizeof(long));
  1652.    farread(help_file, label, num_label*2*sizeof(int));
  1653.  
  1654.    /* finished! */
  1655.  
  1656.    EXIT_OVLY;
  1657.    return (0);    /* success */
  1658.    }
  1659.  
  1660.  
  1661. void end_help(void)
  1662.    {
  1663.    ENTER_OVLY(OVLY_HELP);
  1664.    if (help_file != -1)
  1665.       {
  1666.       close(help_file);
  1667.       farmemfree((BYTE far *)topic_offset);
  1668.       help_file = -1;
  1669.       }
  1670.    EXIT_OVLY;
  1671.    }
  1672.  
  1673.  
  1674.